#ifndef     __BYTE_BUF_H
#define     __BYTE_BUF_H

#include <stdint.h>
#include <malloc.h>
#include "./nocopyable.h"
#include <utility>
#include <memory>

namespace utils {

class SharedByteBuf {

public:
    SharedByteBuf(size_t size = 0) : m_len(size) {
        if (size > 0) {
            m_buf = std::make_shared<uint8_t[]>(size);
        } else {
            m_buf = nullptr;
        }
    }

    inline uint8_t *buf() { return m_buf.get(); }
    inline size_t len() { return m_len; }

private:
    std::shared_ptr<uint8_t[]> m_buf;
    size_t m_len;
};

class ByteBuf : private NoCopyable {

public:
    ByteBuf(size_t size = 0) : m_len(size) {
        if (size > 0) {
            m_buf = (uint8_t *) malloc(size);
        } else {
            m_buf = nullptr;
        }
    }

    ByteBuf(ByteBuf&& other) {
        m_buf = other.m_buf;
        m_len = other.m_len;
        other.m_buf = nullptr;
        other.m_len = 0;
    }

    ByteBuf& operator=(ByteBuf&& other) {
        std::swap(m_buf, other.m_buf);
        std::swap(m_len, other.m_len);
        return *this;
    }

    ~ByteBuf() {
        if (m_buf != nullptr) {
            free(m_buf);
        }
    }
    
    inline uint8_t& operator[](size_t index) {
        return m_buf[index];
    }

    inline const uint8_t& operator[](size_t index) const {
        return m_buf[index];
    }

    inline const uint8_t *buf() const { return m_buf; }

    inline uint8_t *buf() { return m_buf; }
    inline size_t len() const { return m_len; }

private:
    uint8_t *m_buf;
    size_t m_len;
};


}

#endif

